﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using ToodleDo;
using Toodledo.Model;
using Toodledo.Model.API;
using System.Web;

namespace Toodledo.Client
{
	public partial class Session : ITasks
	{
	    #region Implementation of ITasks

	    TaskSet ITasks.GetTasks(TaskQuery query)
	    {
            var factory = new ItemFactory<Task>("task")
                .Element<int>("Id", "id")
                .Element<string>("Name", "title")
                .Element<string>("Tag", "tag")
                .Element<Folder>("Folder", new ItemFactory<Folder>("folder")
                                                 .Value<int>("Id"))
                //.Element<Context>("Context", new ItemFactory<Context>("context")
                //                                 .Attribute<int>("Id", "id")
                //                                 .Value<string>("Name"))
                //.Element<Goal>("Goal", new ItemFactory<Goal>("goal")
                 //                                .Attribute<int>("Id", "id")
                 //                                .Value<string>("Name"))
                .Element<DateTime>("Added", "added")
                .Element<DateTime>("Modified", "modified")
                .Element<DateTime>("Start", "startdate")
                .Element<DateTime>("Due", "duedate")
                //.Element<DateTime>("Due", "duetime")
                .Element<DateTime>("Start", "starttime")
                .Element<int>("Reminder", "remind")//used to be reminder
                .Element<DateTime>("Completed", "completed")
                .Element<Frequency>("Repeat", "repeat")
                .Element<string>("AdvancedRepeat", "rep_advanced")
                .Element<Status>("Status", "status")
                .Element<bool>("HasStar", "star")
                .Element<Priority>("Priority", "priority")
                .Element<int>("Length", "length")
                .Element<string>("Note", "note");

            var results = new TaskSet();
	        var tasks = new List<Task>();

	        var builder = new StringBuilder();


            if (query.ModifiedBefore.HasValue) builder.AppendFormat("modbefore={0};", Util.ToUnix(query.ModifiedBefore));
            if (query.ModifiedAfter.HasValue) builder.AppendFormat("modafter={0};", Util.ToUnix(query.ModifiedAfter));          
            if (query.Id.HasValue) builder.AppendFormat("id={0};", query.Id);        
            //todo add option to load more than 1000 tasks
            //todo add & to enable multiple fields
	        string querystring = builder.ToString();
	        querystring +=
	            "fields=folder,startdate,duedate,duedatemod,starttime,duetime,remind,repeat,status,star,priority,note";
            XDocument response = SendRequest(ActionTypes.GetTasks,querystring);
            foreach (var thisElement in response.Descendants(XName.Get("task", "")))
                tasks.Add(factory.Create(thisElement));

	        results.Tasks = tasks;
            Logger.InvokeMessageEvent(String.Format("Tasks loaded from Toodle: {0}",tasks.Count), Logger.MessageType.Tracking);
            results.Number = ReadAttribute<int>(response.Root, "num");
            results.Total = ReadAttribute<int>(response.Root, "total");
          //  results.PageStart = ReadAttribute<int>(response.Root, "start");
          //  results.PageCount = ReadAttribute<int>(response.Root, "end");
            return results;
        }

        private static string EncodeString(string text)
        {
            return text.Replace("&", "%26").Replace(";", "%3B").Replace(":","%3A");
        }       

	    int ITasks.AddTask(Task task)
	    {
            if (String.IsNullOrEmpty(task.Name))
                throw new InvalidDataException("Task.Name is required");

            var builder = new StringBuilder();
	        builder.Append("tasks=[");
	        builder.Append("{");            
	        builder.Append(FormatArgumentPost(task.Name, "title"));            
            builder.Append("}");
            builder.Append("]");
            //post formatting
	        //string query = builder.ToString().Replace('=', ':').Replace(';','&');
            //todo add & to enable multiple fields
	        string query = EncodeString(builder.ToString());
            XDocument response = SendRequest(ActionTypes.AddTask, query);
            XElement f = response.Descendants(XName.Get("task", "")).FirstOrDefault();
            Logger.InvokeMessageEvent(String.Format("Task added: {0}", task.Name), Logger.MessageType.Tracking);
            return ReadElement<int>(f, "id");//todo add them in a batch
        }

	    bool ITasks.EditTask(Task task)
	    {
            if (task.Id <= 0)
                throw new InvalidDataException("Task.Id is required");

            var builder = new StringBuilder();
            builder.Append("tasks=[");
            builder.Append("{");
            builder.Append(FormatArgumentPost(task.Id, "id"));
            builder.Append(FormatArgumentPost(task.Name, "title"));           
            builder.Append("}");
            builder.Append("]");


            string query = EncodeString(builder.ToString().Replace("\"\"","\",\""));
            XDocument response = SendRequest(ActionTypes.EditTask, query);
            XElement f = response.Descendants(XName.Get("task", "")).FirstOrDefault();
            Logger.InvokeMessageEvent(String.Format("Task edited: {0}", task.Name), Logger.MessageType.Tracking);
            //return ReadElement<int>(f, "id");//todo edit them in a batch
	        return true;
        }

        

	    bool ITasks.DeleteTasks(int[] ids)
	    {
	        string taskids = ids.Aggregate("", (current, id) => current + ("\"" + id + "\"")).Replace("\"\"","\",\"");
	        var parameters = String.Format("tasks=[{0}]",taskids);
            //todo make possible batch delete
            var response = SendRequest(ActionTypes.DeleteTask, parameters);
            Logger.InvokeMessageEvent(String.Format(" {0} Tasks deleted", ids.Length), Logger.MessageType.Tracking);
                return (ReadElement<int>(response) == 1);//todo return all id's that were deleted
        }

	    IEnumerable<DeletedItem> ITasks.GetDeleted(DateTime after)
	    {
	        var factory = new ItemFactory<DeletedItem>("task")
	            .Element<int>("Id", "id")
	            .Element<DateTime>("Deleted", "stamp");
            var results = new List<DeletedItem>();

	        var parameters = String.Format("after={0}", Util.ToUnix(after));
            var response = SendRequest(ActionTypes.GetDeleted, parameters);
            foreach (var thisElement in response.Descendants(XName.Get("task", "")))
                results.Add(factory.Create(thisElement));
            Logger.InvokeMessageEvent("Tasks deleted", Logger.MessageType.Tracking);
            return results;
        }

	    #endregion
	}
}
